package com.jeesite.modules.stock.service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.jeesite.modules.stock.assembler.StockDailyDataAssembler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeesite.common.lang.NumberUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.utils.ClassUtils;
import com.jeesite.modules.stock.dao.StockInformationDao;
import com.jeesite.modules.stock.dao.UserPagesDao;
import com.jeesite.modules.stock.dao.UserStocksDao;
import com.jeesite.modules.stock.dto.UserPageNameUpdateDTO;
import com.jeesite.modules.stock.dto.UserPageStockSearchDTO;
import com.jeesite.modules.stock.dto.UserPageZbConfigDTO;
import com.jeesite.modules.stock.entity.StockInfomationEntity;
import com.jeesite.modules.stock.entity.UserPageEntity;
import com.jeesite.modules.stock.entity.UserStockEntity;

@Service
public class UserStocksService extends AbstractStockService {

    protected Logger log = LoggerFactory.getLogger(UserStocksService.class);

    @Autowired
    private UserPagesDao userPageDao;

    @Autowired
    private UserStocksDao userStocksDao;

    @Autowired
    private StockInformationDao stockInformationDao;

    @Autowired
    private StockRsValuesService stockRsValuesService;

    @Autowired
    private StockDailyDataAssembler assembler;

    String[] defaultUserPageNames = {"我的自选股", "我的持仓"};


    public void addUserPage(String id, String userId, String pageName) {
        if (StringUtils.isBlank(pageName)) {
            throw new RuntimeException("分组名称不能为空");
        }

        if (StringUtils.isBlank(id)) {
            if (userPageDao.pageExist(userId, pageName)) {
                throw new RuntimeException("分组名称[" + pageName + "]已存在");
            }
            List<UserPageEntity> list = userPageDao.findUserPages(userId);
            list.sort(Comparator.comparing(UserPageEntity::getPageNr));

            UserPageEntity entity = new UserPageEntity();
            entity.setUserId(userId);
            entity.setPageName(pageName);
            entity.setPageNr(list.size() + 1);
            entity.setIsSystem(0);
            userPageDao.insert(entity);
        } else {
            UserPageEntity page = userPageDao.get(id);
            page.setPageName(pageName);
            userPageDao.update(page);
        }
    }

    /**
     * 更新分组名称
     *
     * @param dto 参数
     * @return 异常信息
     */
    public String updateUserPageName(UserPageNameUpdateDTO dto) {
        if (StringUtils.isBlank(dto.getPageName())) {
            return "分组名称不能为空";
        }
        UserPageEntity entity = userPageDao.get(dto.getId());
        if (entity != null) {
            List<UserPageEntity> list = userPageDao.findUserPages(entity.getUserId());
            for (UserPageEntity data : list) {
                if (!data.getId().equals(dto.getId()) && dto.getPageName().equals(data.getPageName())) {
                    return "分组名称[" + dto.getPageName() + "]已存在";
                }
            }
            entity.setPageName(dto.getPageName());
            userPageDao.update(entity);

            userStocksDao.updatePageName(entity.getId(), dto.getPageName());

        }
        return "";
    }

    /**
     * 添加自选股票，允许添加到多个分组
     *
     * @param userId     用户id
     * @param pageNames  分组名称
     * @param stockCodes 股票代码
     */
    public void addUserStocks(String userId, List<String> pageNames, List<String> stockCodes) {
        for (String pageName : pageNames) {
            UserPageEntity userPage = userPageDao.findUserPage(userId, pageName);
            if (userPage == null) {
                continue;
            }
            final List<Map<String, Object>> list = userStocksDao.findUserPageStockList(userId, pageName);
            List<String> addStocks = new ArrayList<>(stockCodes);
            addStocks.removeIf(item -> list.stream().anyMatch(d -> item.equals(d.get("stockCode"))));
            for (String stockCode : addStocks) {
                StockInfomationEntity stockInfo = stockInformationDao.findByStockCode(stockCode);
                UserStockEntity entity = new UserStockEntity();
                entity.setUserId(userId);
                entity.setPageName(pageName);
                entity.setStockCode(stockCode);
                entity.setPageId(userPage.getId());
                if (stockInfo != null) {
                    entity.setStockName(stockInfo.getStockName());
                }
                if (!userStocksDao.exist(userId, pageName, stockCode)) {
                    userStocksDao.insert(entity);
                } else {
                    userStocksDao.update(entity);
                }
            }
        }
    }


    private Double getStockConfigData(Map<String, Object> stock, String key) {
        if (stock.containsKey(key)) {
            Object data = stock.get(key);
            if (data != null) {
                switch (data) {
                    case Integer idata -> {
                        return Double.valueOf(idata);
                    }
                    case String s -> {
                        if (NumberUtils.isCreatable(s)) {
                            return Double.parseDouble(s);
                        }
                    }
                    case Float fdata -> {
                        return Double.valueOf(fdata);
                    }
                    case BigDecimal bdata -> {
                        return bdata.doubleValue();
                    }
                    default -> {
                    }
                }
            }
        }
        return null;
    }

    private boolean configMatch(Double sourceData, Double targetData, String condition) {
        if (sourceData != null && targetData != null) {
            if ("gt".equalsIgnoreCase(condition)) {
                return sourceData > targetData;
            } else if ("lt".equalsIgnoreCase(condition)) {
                return sourceData < targetData;
            } else if ("eq".equalsIgnoreCase(condition)) {
                return sourceData.doubleValue() == targetData.doubleValue();
            }
        }
        return false;
    }

    /**
     * 计算自选股票得分
     *
     * @param configArr 指标配置
     * @param stock     股票信息
     * @return 得分
     */
    private double calcStockScore(JSONArray configArr, Map<String, Object> stock) {
        int size = configArr.size();
        double score = 0d;
        double fullScore = 0d;
        for (int i = 0; i < size; i++) {
            JSONObject config = configArr.getJSONObject(i);
            String sourceZbCode = ClassUtils.camelCharset(config.getString("sourceZbCode"));
            String condition = config.getString("condition");
            String targetZbCode = ClassUtils.camelCharset(config.getString("targetZbCode"));
            String targetValue = config.getString("targetValue");
            String targetInputType = config.getString("targetInputType");
            Integer weight = config.getInteger("weight");
            if ("301110".equals(stock.get("stockCode"))) {
                System.out.println();
            }

            Double sourceData = getStockConfigData(stock, sourceZbCode);
            Double targetData = null;
            if ("select".equals(targetInputType)) {
                targetData = getStockConfigData(stock, targetZbCode);
            } else {
                if (!NumberUtils.isCreatable(targetValue)) {
                    continue;
                }
            }
            double rate = weight / 100.0d;
            try {
                if (configMatch(sourceData, targetData == null ? Double.parseDouble(targetValue) : targetData, condition)) {
                    score += (10 * rate);
                }
            } catch (Exception e) {
                log.error("计算自选股票得分失败, errMsg:{}", e.getMessage(), e);
            }
            fullScore += (10 * rate);
        }
        if (score == 0) {
            return 0;
        }
        return BigDecimal.valueOf(score)
                .divide(BigDecimal.valueOf(fullScore), RoundingMode.HALF_UP)
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue();
    }

    /**
     * 计算自选股得分
     *
     * @param configs 配置
     * @param stocks  股票
     */
    private void calcStockScore(String configs, List<Map<String, Object>> stocks) {
        if (!StringUtils.isBlank(configs)) {
            JSONArray arr = JSON.parseArray(configs);
            for (Map<String, Object> stock : stocks) {
                double score = calcStockScore(arr, stock);
                stock.put("score", BigDecimal.valueOf(score).setScale(2, RoundingMode.HALF_UP).floatValue());
            }
        }
    }

    private void userStockSort(List<Map<String, Object>> resList, boolean asc) {
        resList.sort((o1, o2) -> {
            Double score1 = o1.get("score") == null ? -1 : Double.parseDouble(o1.get("score").toString());
            Double score2 = o2.get("score") == null ? -1 : Double.parseDouble(o2.get("score").toString());
            return asc ? score1.compareTo(score2) : score2.compareTo(score1);
        });
    }

    /**
     * 查找分组内得股票
     *
     * @param dto 查询条件
     * @return 用户某个分组下所有的股票
     */
    public List<Map<String, Object>> searchUserPageStockList(UserPageStockSearchDTO dto) {
        UserPageEntity page = userPageDao.findUserPage(dto.getUserId(), dto.getPageName());
        String configs = page.getZbconfigs();
        UserStockEntity condition = new UserStockEntity();
        condition.setStockCode(dto.getStockCode());
        condition.setPageId(page.getId());
        condition.setUserId(dto.getUserId());
        if (!StringUtils.isBlank(dto.getOrderBy()) && !StringUtils.isBlank(dto.getOrder())) {
            if ("industry".equals(dto.getOrderBy())) {
                condition.setOrderBy(" order by si.industry " + dto.getOrder());
            } else {
                condition.setOrderBy(" order by la." + dto.getOrderBy() + " " + dto.getOrder());
            }
        }

        List<Map<String, Object>> list = userStocksDao.searchUserPageStocks(condition);
        List<Map<String, Object>> resList = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (Map<String, Object> data : list) {
                Map<String, Object> dataCr = new HashMap<>();
                for (String key : data.keySet()) {
                    Object value = data.get(key);
                    dataCr.put(ClassUtils.camelCharset(key), value);
                }
                assembler.convert2VO(dataCr);
                resList.add(dataCr);
            }
            calcStockScore(configs, resList);
            if (StringUtils.isBlank(dto.getOrderBy()) || "stock_name".equals(dto.getOrderBy())) {
                userStockSort(resList, "asc".equals(dto.getOrder()));
            }
            stockRsValuesService.appendRsValues(resList);
        }
        return resList;
    }

    private void addDefaultUserPage(String userId) {
        int index = 1;
        for (String pageName : defaultUserPageNames) {
            if (!userPageDao.pageExist(userId, pageName)) {
                UserPageEntity defautPage = new UserPageEntity();
                defautPage.setPageName(pageName);
                defautPage.setPageNr(index++);
                defautPage.setCreateDate(new Date());
                defautPage.setUpdateDate(new Date());
                defautPage.setUserId(userId);
                defautPage.setIsSystem(1);
                userPageDao.insert(defautPage);
            }
        }
    }

    /**
     * 查询用户所有的页面
     *
     * @param userId 用户id
     */
    public List<UserPageEntity> findUserPages(String userId) {
        addDefaultUserPage(userId);
        List<UserPageEntity> list = userPageDao.findUserPages(userId);
        list.forEach(item ->
                item.setStockNum(userStocksDao.getUserPageStockCount(userId, item.getPageName())));
        list.sort(Comparator.comparing(UserPageEntity::getPageNr));
        return list;
    }

    /**
     * 删除分组下的选股
     *
     * @param userId     用户地
     * @param pageName   页面名称
     * @param stockCodes 股票代码
     */
    public void deleteUserStock(String userId, String pageName, List<String> stockCodes) {
        if (stockCodes != null && !stockCodes.isEmpty()) {
            List<UserPageEntity> userPages = new ArrayList<>();
            if (pageName == null) {
                userPages = userPageDao.findUserPages(userId);
            } else {
                UserPageEntity pe = userPageDao.findUserPage(userId, pageName);
                userPages.add(pe);
            }
            if (userPages != null && !userPages.isEmpty()) {
                for (UserPageEntity pe : userPages) {
                    for (String stockCode : stockCodes) {
                        UserStockEntity entity = new UserStockEntity();
                        entity.setUserId(userId);
                        entity.setStockCode(stockCode);
                        entity.setPageId(pe.getId());
                        userStocksDao.deleteUserStock(entity);
                    }
                }
            }
        }
    }

    /**
     * 删除分组
     *
     * @param ids ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserPage(String ids) {
        if (!StringUtils.isBlank(ids)) {
            for (String id : ids.split(",")) {
                UserPageEntity entity = userPageDao.get(id);
                if (entity != null && entity.getIsSystem() != 1) {
                    userPageDao.deleteById(id);
                    List<UserPageEntity> list = userPageDao.findUserPages(entity.getUserId());
                    list.sort(Comparator.comparing(UserPageEntity::getPageNr));
                    int index = 1;
                    for (UserPageEntity pe : list) {
                        pe.setPageNr(index++);
                        userPageDao.update(pe);
                    }
                    // 删除该分组下的股票
                    userStocksDao.deleteUserStockOfPageName(entity.getUserId(), entity.getPageName());
                }
            }
        }
    }

    /**
     * 股票stockCode是否在用户的自选股列表中
     *
     * @param userId    用户id
     * @param stockCode 股票code
     */
    public boolean stockInUserStock(String userId, String stockCode) {
        UserStockEntity entity = new UserStockEntity();
        entity.setUserId(userId);
        entity.setStockCode(stockCode);
        List<Map<String, Object>> list = userStocksDao.searchUserPageStocks(entity);
        return list != null && !list.isEmpty();
    }

    /**
     * 保存用户页面指标配置数据
     *
     * @param dto 指标参数
     */
    public void saveUserPageZbConfig(UserPageZbConfigDTO dto) {
        UserPageEntity entity = userPageDao.findUserPage(dto.getUserId(), dto.getPageName());
        if (entity != null) {
            entity.setZbconfigs(dto.getConfigs());
            userPageDao.update(entity);
        }
    }
}
